home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / lang_c / cug236 / bawkdo.c < prev    next >
Text File  |  1980-01-02  |  13KB  |  782 lines

  1. /*
  2.     HEADER:        CUG000.00;
  3.     TITLE:        BAWK Actions Interpreter;
  4.     DATE:        05/17/1987;
  5.     VERSION:    1.1;
  6.     FILENAME:    BAWKDO.C;
  7.     SEE-ALSO:    BAWK.C;
  8.     AUTHORS:    W. C. Colley III, B. Brodt;
  9. */
  10.  
  11. /*
  12.  * Bawk C actions interpreter
  13.  */
  14. #include <stdio.h>
  15. #include "bawk.h"
  16.  
  17. /* Functions local to this module.    */
  18.  
  19. void expr1(), expr2(), expr3(), expr4(), expr5(), expr6(), expr7(), expr8();
  20. void expr9(), expr10(), postincdec(), preincdec(), primary(), skip();
  21. void skipstatement(), statement();
  22.  
  23. int dopattern( pat )
  24. char *pat;
  25. {
  26.     Where = PATTERN;
  27.     Actptr = pat;
  28.     getoken();
  29.     expression();
  30.     return popint();
  31. }
  32.  
  33. void doaction( act )
  34. char *act;
  35. {
  36.     Where = ACTION;
  37.     Actptr = act;
  38.     getoken();
  39.     while ( Token!=T_EOF )
  40.         statement();
  41. }
  42.  
  43. void expression()
  44. {
  45.     expr1();
  46.     if ( Token==T_ASSIGN ) {
  47.         getoken();  expression();  assignment();
  48.     }
  49. }
  50.  
  51. void expr1()
  52. {
  53.     int ival;
  54.  
  55.     expr2();
  56.     for ( ;; )
  57.     {
  58.         if ( Token==T_LIOR )
  59.         {
  60.             getoken();
  61.             ival = popint();
  62.             expr2();
  63.             pushint( popint() || ival );
  64.         }
  65.         else
  66.             return;
  67.     }
  68. }
  69.  
  70. void expr2()
  71. {
  72.     int ival;
  73.  
  74.     expr3();
  75.     for ( ;; )
  76.     {
  77.         if ( Token==T_LAND )
  78.         {
  79.             getoken();
  80.             ival = popint();
  81.             expr3();
  82.             pushint( popint() && ival );
  83.         }
  84.         else
  85.             return;
  86.     }
  87. }
  88.  
  89. void expr3()
  90. {
  91.     int ival;
  92.  
  93.     expr4();
  94.     for ( ;; )
  95.     {
  96.         if ( Token==T_IOR )
  97.         {
  98.             getoken();
  99.             ival = popint();
  100.             expr4();
  101.             pushint( popint() | ival );
  102.         }
  103.         else
  104.             return;
  105.     }
  106. }
  107.  
  108.  
  109. void expr4()
  110. {
  111.     int ival;
  112.  
  113.     expr5();
  114.     for ( ;; )
  115.     {
  116.         if ( Token==T_AND )
  117.         {
  118.             getoken();
  119.             ival = popint();
  120.             expr5();
  121.             pushint( popint() & ival );
  122.         }
  123.         else
  124.             return;
  125.     }
  126. }
  127.  
  128. void expr5()
  129. {
  130.     int ival;
  131.  
  132.     expr6();
  133.     for ( ;; )
  134.     {
  135.         if ( Token==T_XOR )
  136.         {
  137.             getoken();
  138.             ival = popint();
  139.             expr6();
  140.             pushint( popint() ^ ival );
  141.         }
  142.         else
  143.             return;
  144.     }
  145. }
  146.  
  147. void expr6()
  148. {
  149.     int ival;
  150.  
  151.     expr7();
  152.     for ( ;; )
  153.     {
  154.         if ( Token==T_EQ )
  155.         {
  156.             getoken();
  157.             ival = popint();
  158.             expr7();
  159.             pushint( ival == popint() );
  160.         }
  161.         else if ( Token==T_NE )
  162.         {
  163.             getoken();
  164.             ival = popint();
  165.             expr7();
  166.             pushint( ival != popint() );
  167.         }
  168.         else
  169.             return;
  170.     }
  171. }
  172.  
  173. void expr7()
  174. {
  175.     int ival;
  176.  
  177.     expr8();
  178.     for ( ;; )
  179.     {
  180.         if ( Token==T_LE )
  181.         {
  182.             getoken();
  183.             ival = popint();
  184.             expr8();
  185.             pushint( ival <= popint() );
  186.         }
  187.         else if ( Token==T_GE )
  188.         {
  189.             getoken();
  190.             ival = popint();
  191.             expr8();
  192.             pushint( ival >= popint() );
  193.         }
  194.         else if ( Token==T_LT )
  195.         {
  196.             getoken();
  197.             ival = popint();
  198.             expr8();
  199.             pushint( ival < popint() );
  200.         }
  201.         else if ( Token==T_GT )
  202.         {
  203.             getoken();
  204.             ival = popint();
  205.             expr8();
  206.             pushint( ival > popint() );
  207.         }
  208.         else
  209.             return;
  210.     }
  211. }
  212.  
  213. void expr8()
  214. {
  215.     int ival;
  216.  
  217.     expr9();
  218.     for ( ;; )
  219.     {
  220.         if ( Token==T_SHL )
  221.         {
  222.             getoken();
  223.             ival = popint();
  224.             expr9();
  225.             pushint( ival << popint() );
  226.         }
  227.         else if ( Token==T_SHR )
  228.         {
  229.             getoken();
  230.             ival = popint();
  231.             expr9();
  232.             pushint( ival >> popint() );
  233.         }
  234.         else
  235.             return;
  236.     }
  237. }
  238.  
  239. void expr9()
  240. {
  241.     int ival;
  242.  
  243.     expr10();
  244.     for ( ;; )
  245.     {
  246.         if ( Token==T_ADD )
  247.         {
  248.             getoken();
  249.             ival = popint();
  250.             expr10();
  251.             pushint( ival + popint() );
  252.         }
  253.         else if ( Token==T_SUB )
  254.         {
  255.             getoken();
  256.             ival = popint();
  257.             expr10();
  258.             pushint( ival - popint() );
  259.         }
  260.         else
  261.             return;
  262.     }
  263. }
  264.  
  265. void expr10()
  266. {
  267.     int ival;
  268.  
  269.     primary();
  270.     for ( ;; )
  271.     {
  272.         if ( Token==T_MUL )
  273.         {
  274.             getoken();
  275.             ival = popint();
  276.             primary();
  277.             pushint( ival * popint() );
  278.         }
  279.         else if ( Token==T_DIV )
  280.         {
  281.             getoken();
  282.             ival = popint();
  283.             primary();
  284.             pushint( ival / popint() );
  285.         }
  286.         else if ( Token==T_MOD )
  287.         {
  288.             getoken();
  289.             ival = popint();
  290.             primary();
  291.             pushint( ival % popint() );
  292.         }
  293.         else
  294.             return;
  295.     }
  296. }
  297.  
  298. void primary()
  299. {
  300.     int index;
  301.     DATUM data;
  302.     VARIABLE *pvar;
  303.  
  304.     switch ( Token )
  305.     {
  306.     case T_LPAREN:
  307.         /*
  308.          * it's a parenthesized expression
  309.          */
  310.         getoken();
  311.         expression();
  312.         if ( Token!=T_RPAREN )
  313.             error( "missing ')'", ACT_ERROR );
  314.         getoken();
  315.         break;
  316.     case T_LNOT:
  317.         getoken();
  318.         primary();
  319.         pushint( ! popint() );
  320.         break;
  321.     case T_NOT:
  322.         getoken();
  323.         primary();
  324.         pushint( ~ popint() );
  325.         break;
  326.     case T_ADD:
  327.         getoken();
  328.         primary();
  329.         break;
  330.     case T_SUB:
  331.         getoken();
  332.         primary();
  333.         pushint( - popint() );
  334.         break;
  335.     case T_INCR:
  336.     case T_DECR:
  337.         preincdec();
  338.         break;
  339.     case T_MUL:
  340.         getoken();
  341.         primary();
  342.         /*
  343.          * If item on stack is an LVALUE, do an extra level of
  344.          * indirection before changing it to an LVALUE.
  345.          */
  346.         if ( Stackptr->lvalue )
  347.             Stackptr->value.dptr = *Stackptr->value.ptrptr;
  348.         Stackptr->lvalue = 1;
  349.         --Stackptr->class;
  350.         break;
  351.     case T_AND:
  352.         getoken();
  353.         primary();
  354.         if ( Stackptr->lvalue )
  355.             Stackptr->lvalue = 0;
  356.         else
  357.             error( "'&' operator needs an lvalue", ACT_ERROR );
  358.         break;
  359.     case T_CONSTANT:
  360.         pushint( Value.ival );
  361.         getoken();
  362.         break;
  363.     case T_REGEXP:
  364.         /*
  365.          * It's a regular expression - parse it and compile it.
  366.          */
  367.         if ( Where == PATTERN )
  368.         {
  369.             /*
  370.              * We're processing a pattern right now - perform a
  371.              * match of the regular expression agains input line.
  372.              */
  373.             unparse( Fields, Fieldcount, Linebuf, Fldsep );
  374.             pushint( match( Linebuf, Value.dptr ) );
  375.         }
  376.         else
  377.             push( 1, ACTUAL, BYTE, &Value );
  378.         getoken();
  379.         break;
  380.     case T_NF:
  381.         pushint( Fieldcount );
  382.         getoken();
  383.         break;
  384.     case T_NR:
  385.         pushint( Recordcount );
  386.         getoken();
  387.         break;
  388.     case T_FS:
  389.         Fldsep[1] = 0;
  390.         data.dptr = Fldsep;
  391.         push( 0, LVALUE, BYTE, &data );
  392.         getoken();
  393.         break;
  394.     case T_RS:
  395.         Rcrdsep[1] = 0;
  396.         data.dptr = Rcrdsep;
  397.         push( 0, LVALUE, BYTE, &data );
  398.         getoken();
  399.         break;
  400.     case T_FILENAME:
  401.         data.dptr = Filename;
  402.         push( 1, ACTUAL, BYTE, &data );
  403.         getoken();
  404.         break;
  405.     case T_DOLLAR:
  406.         /*
  407.          * It's a reference to one (or all) of the words in Linebuf.
  408.          */
  409.         getoken();
  410.         primary();
  411.         if ( index = popint() )
  412.         {
  413.             if ( index > Fieldcount )
  414.                 index = Fieldcount;
  415.             else if ( index < 1 )
  416.                 index = 1;
  417.             data.dptr = Fields[ index-1 ];
  418.         }
  419.         else
  420.         {
  421.             /*
  422.              * Reconstitute the line buffer in case any of the
  423.              * fields have been changed.
  424.              */
  425.             unparse( Fields, Fieldcount, Linebuf, Fldsep );
  426.             data.dptr = Linebuf;
  427.         }
  428.         /*
  429.          * $<expr>'s are treated the same as string constants:
  430.          */
  431.         push( 1, ACTUAL, BYTE, &data );
  432.         break;
  433.     case T_STRING:
  434.         push( 1, ACTUAL, BYTE, &Value );
  435.         getoken();
  436.         break;
  437.     case T_FUNCTION:
  438.         /*
  439.          * Do a built-in function call
  440.          */
  441.         index = Value.ival;
  442.         getoken();
  443.         function( index );
  444.         break;
  445.     case T_VARIABLE:
  446.         pvar = (VARIABLE *)Value.dptr;
  447.         getoken();
  448.         /*
  449.          * it's a plain variable. The way a variable is
  450.          * represented on the stack depends on its type:
  451.          *    lvalue class value.dptr
  452.          * vars:  1     0   address of var
  453.          * ptrs:  1     1   address of ptr to var
  454.          * array: 0     1   address of var
  455.          */
  456.         if ( pvar->vclass && !pvar->vlen )
  457.             /* it's a pointer */
  458.             data.ptrptr = &pvar->vptr;
  459.         else
  460.             /* an array or simple variable */
  461.             data.dptr = pvar->vptr;
  462.         /*
  463.          * If it's an array it can't be used as an LVALUE.
  464.          */
  465.         push( pvar->vclass, !pvar->vlen, pvar->vsize, &data );
  466.         break;
  467.     case T_EOF:
  468.         break;
  469.     default:
  470.         syntaxerror();
  471.     }
  472.     /*
  473.      * a "[" means it's an array reference
  474.      */
  475.     if ( Token==T_LBRACKET )
  476.     {
  477.         getoken();
  478.         if ( ! Stackptr->class )
  479.             error( "'[]' needs an array or pointer", ACT_ERROR );
  480.         /*
  481.          * compute the subscript
  482.          */
  483.         expression();
  484.         if ( Token!=T_RBRACKET )
  485.             error( "missing ']'", ACT_ERROR );
  486.         getoken();
  487.         index = popint();
  488.         /*
  489.          * compute the offset (subscript times two for int arrays)
  490.          * and then the effective address.
  491.          */
  492.         index *= Stackptr->size;
  493.         if ( Stackptr->lvalue )
  494.             /*
  495.              * It's a pointer - don't forget that the stack top
  496.              * item's value is the address of the pointer so we
  497.              * must do another level of indirection.
  498.              */
  499.             Stackptr->value.dptr =
  500.                 *(Stackptr->value.ptrptr) + index;
  501.         else
  502.             /*
  503.              * It's a plain array - the stack top item's value is
  504.              * the address of the first element in the array.
  505.              */
  506.             Stackptr->value.dptr += index;
  507.  
  508.         /*
  509.          * The stack top item now becomes an LVALUE, but we've
  510.          * reduced the indirection level.
  511.          */
  512.         Stackptr->lvalue = 1;
  513.         --Stackptr->class;
  514.     }
  515.  
  516.     if ( Token==T_INCR || Token==T_DECR )
  517.         postincdec();
  518. }
  519.  
  520. void preincdec()
  521. {
  522.     /*
  523.      * Pre increment/decrement
  524.      */
  525.     int incr;
  526.  
  527.     incr = Token==T_INCR ? 1 : -1;
  528.     getoken();
  529.     primary();
  530.     if ( Stackptr->lvalue )
  531.     {
  532.         if ( Stackptr->class )
  533.             incr *= Stackptr->size;
  534.         *(Stackptr->value.ptrptr) += incr;
  535.     }
  536.     else
  537.         error( "pre '++' or '--' needs an lvalue", ACT_ERROR );
  538. }
  539.  
  540. void postincdec()
  541. {
  542.     /*
  543.      * Post increment/decrement
  544.      */
  545.     char *p;
  546.     int i, incr;
  547.  
  548.     incr = Token==T_INCR ? 1 : -1;
  549.     getoken();
  550.     if ( Stackptr->lvalue )
  551.     {
  552.         if ( Stackptr->class )
  553.         {
  554.             /*
  555.              * It's a pointer - save its old value then
  556.              * increment/decrement the pointer.  This makes the
  557.              * item on top of the stack look like an array, which
  558.              * means it can no longer be used as an LVALUE. This
  559.              * doesn't really hurt, since it doesn't make much
  560.              * sense to say:
  561.              *   char *cp;
  562.              *   cp++ = value;
  563.              */
  564.             p = *(Stackptr->value.ptrptr);
  565.             *(Stackptr->value.ptrptr) += incr * Stackptr->size;
  566.             Stackptr->value.dptr = p;
  567.         }
  568.         else
  569.         {
  570.             /*
  571.              * It's a simple variable - save its old value then
  572.              * increment/decrement the variable.  This makes the
  573.              * item on top of the stack look like a constant,
  574.              * which means it can no longer be used as an LVALUE.
  575.              * Same reasoning as above.
  576.              */
  577.             if ( Stackptr->size == BYTE )
  578.                 i = *(Stackptr->value.dptr);
  579.             else
  580.                 i = *((int *)Stackptr->value.dptr);
  581.             *(Stackptr->value.ptrptr) += incr;
  582.             Stackptr->value.ival = i;
  583.         }
  584.         Stackptr->lvalue = 0;
  585.     }
  586.     else
  587.         error( "post '++' or '--' needs an lvalue", ACT_ERROR );
  588. }
  589.  
  590. void statement()
  591. {
  592.     /*
  593.      * Evaluate a statement
  594.      */
  595.     char *repeat, *body;
  596.  
  597.     switch ( Token )
  598.     {
  599.     case T_EOF:
  600.         break;
  601.     case T_CHAR:
  602.     case T_INT:
  603.         declist();
  604.         break;
  605.     case T_LBRACE:
  606.         /*
  607.          * parse a compound statement
  608.          */
  609.         getoken();
  610.         while ( !Saw_break && Token!=T_RBRACE )
  611.             statement();
  612.  
  613.         if ( Token==T_RBRACE )
  614.             getoken();
  615.         break;
  616.     case T_IF:
  617.         /*
  618.          * parse an "if-else" statement
  619.          */
  620.         if ( getoken() != T_LPAREN )
  621.             syntaxerror();
  622.         getoken();
  623.         expression();
  624.         if ( Token!=T_RPAREN )
  625.             syntaxerror();
  626.         getoken();
  627.         if ( popint() )
  628.         {
  629.             statement();
  630.             if ( Token==T_ELSE )
  631.             {
  632.                 getoken();
  633.                 skipstatement();
  634.             }
  635.         }
  636.         else
  637.         {
  638.             skipstatement();
  639.             if ( Token==T_ELSE )
  640.             {
  641.                 getoken();
  642.                 statement();
  643.             }
  644.         }
  645.         break;
  646.     case T_WHILE:
  647.         /*
  648.          * parse a "while" statement
  649.          */
  650.         repeat = Actptr;
  651.         for ( ;; )
  652.         {
  653.             if ( getoken() != T_LPAREN )
  654.                 syntaxerror();
  655.  
  656.             getoken();
  657.             expression();
  658.             if ( Token!=T_RPAREN )
  659.                 syntaxerror();
  660.  
  661.             if ( popint() )
  662.             {
  663.                 body = Actptr;
  664.                 getoken();
  665.                 statement();
  666.                 if ( Saw_break )
  667.                 {
  668.                     Actptr = body;
  669.                     Saw_break = 0;
  670.                     break;
  671.                 }
  672.                 Actptr = repeat;
  673.             }
  674.             else
  675.                 break;
  676.         }
  677.         getoken();
  678.         skipstatement();
  679.         break;
  680.     case T_BREAK:
  681.         /*
  682.          * parse a "break" statement
  683.          */
  684.         getoken();
  685.         Saw_break = 1;
  686.         break;
  687.     case T_SEMICOLON:
  688.         break;
  689.     default:
  690.         expression();
  691.         popint();
  692.     }
  693.  
  694.     if ( Token==T_SEMICOLON )
  695.         getoken();
  696. }
  697.  
  698. void skipstatement()
  699. {
  700.     /*
  701.      * Skip a statement
  702.      */
  703.  
  704.     switch ( Token )
  705.     {
  706.     case T_LBRACE:
  707.         /*
  708.          * skip a compound statement
  709.          */
  710.         skip( T_LBRACE, T_RBRACE );
  711.         break;
  712.     case T_IF:
  713.         /*
  714.          * skip an "if-else" statement
  715.          */
  716.         getoken();    /* skip 'if' */
  717.         skip( T_LPAREN, T_RPAREN );
  718.         skipstatement();
  719.         if ( Token==T_ELSE )
  720.         {
  721.             getoken();    /* skip 'else' */
  722.             skipstatement();
  723.         }
  724.         break;
  725.     case T_WHILE:
  726.         /*
  727.          * skip a "while" statement
  728.          */
  729.         getoken();    /* skip 'while' */
  730.         skip( T_LPAREN, T_RPAREN );
  731.         skipstatement();
  732.         break;
  733.     default:
  734.         /*
  735.          * skip a one-liner
  736.          */
  737.         while (Token!=T_SEMICOLON && Token!=T_RBRACE && Token!=T_EOF)
  738.             getoken();
  739.         if ( Token==T_EOF )
  740.             error( "unexpected end", ACT_ERROR );
  741.         if ( Token==T_SEMICOLON )
  742.             getoken();
  743.     }
  744. }
  745.  
  746. void skip( left, right )
  747. char left, right;
  748. {
  749.     /*
  750.      * Skip matched left and right delimiters and everything in between
  751.      */
  752.     int parity;
  753.     char *save, errmsg[ 80 ];
  754.  
  755.     parity = 1;
  756.     save = Actptr;
  757.     while ( getoken() != T_EOF )
  758.     {
  759.         if ( Token == left )
  760.         {
  761.             save = Actptr;
  762.             ++parity;
  763.         }
  764.         else if ( Token == right )
  765.             --parity;
  766.         if ( !parity )
  767.         {
  768.             getoken();
  769.             return;
  770.         }
  771.     }
  772.     Actptr = save;
  773.  
  774.     (void)sprintf(errmsg,"mismatched '%c' and '%c'",left,right);
  775.     error( errmsg, ACT_ERROR );
  776. }
  777.  
  778. void syntaxerror()
  779. {
  780.     error( "syntax error", ACT_ERROR );
  781. }
  782.